# -*- coding: utf8 -*-
"""
Hopf algebra : some pattern use to compute fundamental basis and is dual.

AUTHOR:

- Jean-Baptiste Priez
"""
#*****************************************************************************
#       Copyright (C) 2012 Jean-Baptiste Priez <jbp@kerios.fr>,
#
#  Distributed under the terms of the GNU General Public License (GPL)
#
#    This code is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#    General Public License for more details.
#
#  The full text of the GPL is available at:
#
#                  http://www.gnu.org/licenses/
#*****************************************************************************
def getitem_for_wordlike_indices ( self, c, *rest ):
    """
    This method implements the abuses of notations::

        F[1,3,2]
        F[[1,3,2]]
        F[FQSym.indices()([2,1])]

    .. todo::

        This should call ``super.monomial`` if the input can't
        be made into a composition so as not to interfere with
        the standard notation ``Psi['x,y,z']``.

        This could possibly be shared with Sym, FQSym, and
        other algebras with bases indexed by list-like objects
    """
    from sage.rings.integer import Integer
    from sage.structure.element import parent
    indices = self.realization_of().indices()
    if parent( c ) is indices: #indices.is_parent_of( c ):
        assert len( rest ) == 0
    else:
        if len( rest ) > 0 or isinstance( c, ( int, Integer ) ):
            c = indices( [c] + list( rest ) )
        else:
            c = indices( list( c ) )
    return self.monomial( c )

from sage.combinat.free_module import CombinatorialFreeModule
class GenericBasis( CombinatorialFreeModule ):

    def __init__( self, HopfAlg ):
        r"""

        EXAMPLES::
    
            sage: F = FQSym(QQ).F()
            sage: F[3,1,2] * F[1,2] # shifted shuffle of [3,1,2] and [1,2]
            F[3, 1, 2, 4, 5] + F[3, 1, 4, 2, 5] + F[3, 1, 4, 5, 2] + F[3, 4, 1, 2, 5] + F[3, 4, 1, 5, 2] + F[3, 4, 5, 1, 2] + F[4, 3, 1, 2, 5] + F[4, 3, 1, 5, 2] + F[4, 3, 5, 1, 2] + F[4, 5, 3, 1, 2]
            sage: F[3,1,2,4].coproduct() # deconcatenation of [3,1,2,4]
            F[] # F[3, 1, 2, 4] + F[1] # F[1, 2, 3] + F[2, 1] # F[1, 2] + F[3, 1, 2] # F[1] + F[3, 1, 2, 4] # F[]
        """
        CombinatorialFreeModule.__init__( 
            self, HopfAlg.base_ring(), HopfAlg.indices(),
            category = HopfAlg.Bases() )

    __getitem__ = getitem_for_wordlike_indices

class FundamentalBasis( GenericBasis ):

    def product_on_basis( self, e1, e2 ):
        ''' Shifted shuffle
        It's not optimal for any algebra
        '''
        from sage.combinat.words.word import Word
        from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
        C = lambda x: self.phi( list( x ) )
        w1 = Word( e1 )
        w2 = Word( self.shift( e1, e2 ) )
        return self.sum_of_monomials( C( c )
            for c in ShuffleProduct_w1w2( w1, w2 ) )

    def coproduct_on_basis( self, e ):
        '''
        Deconcatenation
        '''
        phi = self.phi
        return self.tensor_square().sum_of_monomials( 
            ( phi( e[:i] ), phi( e[i:] ) ) for i in range( len( e ) + 1 ) )

class FundamentalDualBasis( GenericBasis ):

    def product_on_basis( self, e1, e2 ):
        ''' Concatenation ::==:: convolution product
            This implementation is a formal approch... must be code for each
            different algebra
        '''
        from sage.combinat.words.words import Words
        from sage.sets.set import Set
        set_w = Words( len( e1 ) + len( e2 ), len( list( e1 ) ) + len ( list ( e2 ) ) )
        tmp = []; i = len ( e1 )
        phi = self.phi
        for w in set_w :
            if phi ( list( w[:i] ) ) == e1 and phi ( list( w[i:] ) ) == e2 :
                tmp.append( phi ( list( w ) ) )
        return self.sum_of_monomials ( Set( tmp ) )

    def coproduct_on_basis( self, e ):
        ''' UnShifted shuffle
        '''
        from sage.sets.set import Set
        def restriction( w, i ):
            r''' Restriction of intervalle [min, i] and [i+1, max]

            TESTS::

                sage: restriction([],0)
                ([], [])
                sage: restriction([],1)
                ([], [])
                sage: restriction([4,3,2,3,1,4],3)
                ([3,2,3,1], [4,4])
                sage: tup = restriction(Composition([4,3,2,3,1,4]),3, constr = Composition);tup
                ([3, 2, 3, 1], [4, 4])
                sage: type(tup[0])
                <class 'sage.combinat.composition.Composition_class'>
                sage: from sage.combinat.permutation import to_standard
                sage: tup = restriction(Permutation([4,1,2,3]),2, f = to_standard,constr = Permutation);tup
                ([1, 2], [2, 1])
                sage: type(tup[1])
                <class 'sage.combinat.permutation.Permutation_class'>
                sage: restriction([4,1,2,3],2, f = to_standard, couple = tensor)
                sage: F = FreeQuasisymmetricFunctions(QQ).Fundamental()
                sage: restriction([4,1,2,3],2, f = to_standard, constr = lambda x: F.monomial(Permutation(x)), couple = tensor)
                F[1, 2] # F[2, 1]
            '''
            left = []
            right = []
            for l in w :
                if l >= i + 1: right.append( l )
                else: left.append( l )
            return ( self.indices()( left ), self.phi( right ) )

        return self.tensor_square().sum_of_monomials( 
            restriction( e, i )
            for i in Set( [-1] + list( e ) ) )
